home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / netconnect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  60.9 KB  |  1,621 lines

  1. //-----------------------------------------------------------------------------
  2. // File: NetConnect.cpp
  3. //
  4. // Desc: This is a class that given a IDirectPlay8Peer, then DoConnectWizard()
  5. //       will enumerate service providers, enumerate hosts, and allow the
  6. //       user to either join or host a session.  The class uses
  7. //       dialog boxes and GDI for the interactive UI.  Most games will
  8. //       want to change the graphics to use Direct3D or another graphics
  9. //       layer, but this simplistic sample uses dialog boxes.  Feel 
  10. //       free to use this class as a starting point for adding extra 
  11. //       functionality.
  12. //
  13. //
  14. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. #define STRICT
  17. #include <windows.h>
  18. #include <basetsd.h>
  19. #include <stdio.h>
  20. #include <mmsystem.h>
  21. #include <dxerr8.h>
  22. #include <dplay8.h>
  23. #include <dpaddr.h>
  24. #include <dplobby8.h>
  25. #include "NetConnect.h"
  26. #include "NetConnectRes.h"
  27. #include "DXUtil.h"
  28.  
  29.  
  30.  
  31.  
  32. //-----------------------------------------------------------------------------
  33. // Global variables
  34. //-----------------------------------------------------------------------------
  35. CNetConnectWizard* g_pNCW = NULL;           // Pointer to the net connect wizard
  36.  
  37.  
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Name: CNetConnectWizard
  42. // Desc: Init the class
  43. //-----------------------------------------------------------------------------
  44. CNetConnectWizard::CNetConnectWizard( HINSTANCE hInst, HWND hWndParent, 
  45.                                       TCHAR* strAppName, GUID* pGuidApp )
  46. {
  47.     g_pNCW              = this;
  48.     m_hInst             = hInst;
  49.     m_hWndParent        = hWndParent;
  50.     m_pDP               = NULL;
  51.     m_pLobbiedApp       = NULL;
  52.     m_bHaveConnectionSettingsFromLobby = FALSE;
  53.     m_hLobbyClient      = NULL;
  54.     m_guidApp           = *pGuidApp;
  55.     m_hDlg              = NULL;
  56.     m_bConnecting       = FALSE;
  57.     m_hConnectAsyncOp   = NULL;
  58.     m_pDeviceAddress    = NULL;
  59.     m_pHostAddress      = NULL;
  60.     m_hEnumAsyncOp      = NULL;
  61.     m_bMigrateHost      = FALSE;
  62.     m_dwEnumHostExpireInterval = 0;
  63.  
  64.     // Set the max players unlimited by default.  This can be changed by the app
  65.     // by calling SetMaxPlayers()
  66.     m_dwMaxPlayers   = 0;
  67.  
  68.     _tcscpy( m_strAppName, strAppName );
  69.     _tcscpy( m_strPreferredProvider, TEXT("DirectPlay8 TCP/IP Service Provider") );
  70.  
  71.     InitializeCriticalSection( &m_csHostEnum );
  72.     m_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  73.     m_hLobbyConnectionEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  74.  
  75.     // Setup the m_DPHostEnumHead circular linked list
  76.     ZeroMemory( &m_DPHostEnumHead, sizeof( DPHostEnumInfo ) );
  77.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  78. }
  79.  
  80.  
  81.  
  82.  
  83. //-----------------------------------------------------------------------------
  84. // Name: ~CNetConnectWizard
  85. // Desc: Cleanup the class
  86. //-----------------------------------------------------------------------------
  87. CNetConnectWizard::~CNetConnectWizard()
  88. {
  89.     DeleteCriticalSection( &m_csHostEnum );
  90.     CloseHandle( m_hConnectCompleteEvent );
  91.     CloseHandle( m_hLobbyConnectionEvent );
  92. }
  93.  
  94.  
  95.  
  96. //-----------------------------------------------------------------------------
  97. // Name: Init
  98. // Desc:
  99. //-----------------------------------------------------------------------------
  100. VOID CNetConnectWizard::Init( IDirectPlay8Peer* pDP,
  101.                               IDirectPlay8LobbiedApplication* pLobbiedApp )
  102. {
  103.     m_pDP               = pDP;
  104.     m_pLobbiedApp       = pLobbiedApp;
  105.     m_bHaveConnectionSettingsFromLobby = FALSE;
  106.     m_hLobbyClient      = NULL;
  107. }
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Name: Shutdown
  113. // Desc: Releases the DirectPlay interfaces
  114. //-----------------------------------------------------------------------------
  115. VOID CNetConnectWizard::Shutdown()
  116. {
  117.     SAFE_RELEASE( m_pDeviceAddress );
  118.     SAFE_RELEASE( m_pHostAddress );
  119. }
  120.  
  121.  
  122.  
  123.  
  124. //-----------------------------------------------------------------------------
  125. // Name: DoConnectWizard
  126. // Desc: This is the main external function.  This will launch a series of
  127. //       dialog boxes that enumerate service providers, enumerate hosts,
  128. //       and allow the user to either join or host a session
  129. //-----------------------------------------------------------------------------
  130. HRESULT CNetConnectWizard::DoConnectWizard( BOOL bBackTrack )
  131. {
  132.     if( m_pDP == NULL )
  133.         return E_INVALIDARG;
  134.  
  135.     int nStep;
  136.  
  137.     // If the back track flag is true, then the user has already been through
  138.     // the connect process once, and has back tracked out of the main game
  139.     // so start at the last dialog box
  140.     if( bBackTrack )
  141.         nStep = 1;
  142.     else
  143.         nStep = 0;
  144.  
  145.     // Show the dialog boxes to connect
  146.     while( TRUE )
  147.     {
  148.         m_hrDialog = S_OK;
  149.  
  150.         switch( nStep )
  151.         {
  152.             case 0:
  153.                 // Display the multiplayer connect dialog box.
  154.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CONNECT),
  155.                            m_hWndParent, (DLGPROC) StaticConnectionsDlgProc );
  156.                 break;
  157.  
  158.             case 1:
  159.                 // Display the multiplayer games dialog box.
  160.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_GAMES),
  161.                            m_hWndParent, (DLGPROC) StaticSessionsDlgProc );
  162.                 break;
  163.         }
  164.  
  165.         if( FAILED( m_hrDialog ) ||
  166.             m_hrDialog == NCW_S_QUIT ||
  167.             m_hrDialog == NCW_S_LOBBYCONNECT )
  168.             break;
  169.  
  170.         if( m_hrDialog == NCW_S_BACKUP )
  171.             nStep--;
  172.         else
  173.             nStep++;
  174.  
  175.         // If we go beyond the last step in the wizard, then stop
  176.         // and return.
  177.         if( nStep == 2 )
  178.             break;
  179.     }
  180.  
  181.     // Depending upon a successful m_hrDialog the user has
  182.     // either successfully join or created a game, depending on m_bHostPlayer
  183.     m_pDP = NULL;
  184.     return m_hrDialog;
  185. }
  186.  
  187.  
  188.  
  189.  
  190. //-----------------------------------------------------------------------------
  191. // Name: StaticConnectionsDlgProc()
  192. // Desc: Static msg handler which passes messages
  193. //-----------------------------------------------------------------------------
  194. INT_PTR CALLBACK CNetConnectWizard::StaticConnectionsDlgProc( HWND hDlg, UINT uMsg,
  195.                                                               WPARAM wParam, LPARAM lParam )
  196. {
  197.     if( g_pNCW )
  198.         return g_pNCW->ConnectionsDlgProc( hDlg, uMsg, wParam, lParam );
  199.  
  200.     return FALSE; // Message not handled
  201. }
  202.  
  203.  
  204.  
  205.  
  206. //-----------------------------------------------------------------------------
  207. // Name: ConnectionsDlgProc()
  208. // Desc: Handles messages for the multiplayer connect dialog
  209. //-----------------------------------------------------------------------------
  210. INT_PTR CALLBACK CNetConnectWizard::ConnectionsDlgProc( HWND hDlg, UINT msg,
  211.                                                         WPARAM wParam, LPARAM lParam )
  212. {
  213.     switch( msg )
  214.     {
  215.         case WM_INITDIALOG:
  216.             {
  217.                 SetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName );
  218.  
  219.                 // Load and set the icon
  220.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  221.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  222.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  223.  
  224.                 // Set the window title
  225.                 TCHAR strWindowTitle[256];
  226.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Connect"), m_strAppName );
  227.                 SetWindowText( hDlg, strWindowTitle );
  228.  
  229.                 // Fill the list box with the service providers
  230.                 if( FAILED( m_hrDialog = ConnectionsDlgFillListBox( hDlg ) ) )
  231.                 {
  232.                     DXTRACE_ERR( TEXT("ConnectionsDlgFillListBox"), m_hrDialog );
  233.                     EndDialog( hDlg, 0 );
  234.                 }
  235.             }
  236.             break;
  237.  
  238.         case WM_COMMAND:
  239.             switch( LOWORD(wParam) )
  240.             {
  241.                 case IDC_CONNECTION_LIST:
  242.                     if( HIWORD(wParam) != LBN_DBLCLK )
  243.                         break;
  244.                     // Fall through
  245.  
  246.                 case IDOK:
  247.                     if( FAILED( m_hrDialog = ConnectionsDlgOnOK( hDlg ) ) )
  248.                     {
  249.                         DXTRACE_ERR( TEXT("ConnectionsDlgOnOK"), m_hrDialog );
  250.                         EndDialog( hDlg, 0 );
  251.                     }
  252.  
  253.                     if( m_hrDialog == NCW_S_LOBBYCONNECT )
  254.                     {
  255.                         EndDialog( hDlg, 0 );
  256.                     }
  257.                     break;
  258.  
  259.                 case IDCANCEL:
  260.                     m_hrDialog = NCW_S_QUIT;
  261.                     EndDialog( hDlg, 0 );
  262.                     break;
  263.  
  264.                 default:
  265.                     return FALSE; // Message not handled
  266.             }
  267.             break;
  268.  
  269.         case WM_DESTROY:
  270.             ConnectionsDlgCleanup( hDlg );
  271.             break;
  272.  
  273.         default:
  274.             return FALSE; // Message not handled
  275.     }
  276.  
  277.     // Message was handled
  278.     return TRUE;
  279. }
  280.  
  281.  
  282.  
  283.  
  284. //-----------------------------------------------------------------------------
  285. // Name: ConnectionsDlgFillListBox()
  286. // Desc: Fills the DirectPlay connection listbox with service providers,
  287. //       and also adds a "Wait for Lobby" connection option.
  288. //-----------------------------------------------------------------------------
  289. HRESULT CNetConnectWizard::ConnectionsDlgFillListBox( HWND hDlg )
  290. {
  291.     HRESULT                     hr;
  292.     int                         iLBIndex;
  293.     DWORD                       dwItems     = 0;
  294.     DPN_SERVICE_PROVIDER_INFO*  pdnSPInfo   = NULL;
  295.     DWORD                       dwSize      = 0;
  296.     HWND                        hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  297.     TCHAR                       strName[MAX_PATH];
  298.  
  299.     // Enumerate all DirectPlay service providers, and store them in the listbox
  300.     dwSize = 1024;
  301.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  302.     hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
  303.                                       &dwItems, 0 );
  304.     if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  305.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  306.     if( hr == DPNERR_BUFFERTOOSMALL )
  307.     {
  308.         SAFE_DELETE( pdnSPInfo );
  309.         pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  310.         if( FAILED( hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
  311.                                                       &dwSize, &dwItems, 0 ) ) )
  312.             return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  313.     }
  314.  
  315.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  316.     for ( DWORD i = 0; i < dwItems; i++ )
  317.     {
  318.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  319.  
  320.         // Found a service provider, so put it in the listbox
  321.         iLBIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  322.                                      (LPARAM)strName );
  323.         if( iLBIndex == CB_ERR )
  324.             return E_FAIL; // Error, stop enumerating
  325.  
  326.         // Store pointer to GUID in listbox
  327.         GUID* pGuid = new GUID;
  328.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  329.         SendMessage( hWndListBox, LB_SETITEMDATA, iLBIndex,
  330.                      (LPARAM)pGuid );
  331.  
  332.         pdnSPInfoEnum++;
  333.     }
  334.  
  335.     SAFE_DELETE( pdnSPInfo );
  336.  
  337.     // Add "Wait for Lobby Connection" selection in list box
  338.     SendMessage( hWndListBox, LB_ADDSTRING, 0,
  339.                  (LPARAM) TEXT("Wait for Lobby Connection") );
  340.  
  341.     SetFocus( hWndListBox );
  342.  
  343.     // Try to select the default preferred provider
  344.     iLBIndex = (int)SendMessage( hWndListBox, LB_FINDSTRINGEXACT, (WPARAM)-1,
  345.                                 (LPARAM)m_strPreferredProvider );
  346.     if( iLBIndex != LB_ERR )
  347.         SendMessage( hWndListBox, LB_SETCURSEL, iLBIndex, 0 );
  348.     else
  349.         SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  350.  
  351.  
  352.     return S_OK;
  353. }
  354.  
  355.  
  356.  
  357.  
  358. //-----------------------------------------------------------------------------
  359. // Name: ConnectionsDlgOnOK()
  360. // Desc: Stores the player name m_strPlayerName, and in creates a IDirectPlay
  361. //       object based on the connection type the user selected.
  362. //-----------------------------------------------------------------------------
  363. HRESULT CNetConnectWizard::ConnectionsDlgOnOK( HWND hDlg )
  364. {
  365.     LRESULT iIndex;
  366.     HRESULT hr;
  367.  
  368.     GetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName, MAX_PATH );
  369.  
  370.     if( _tcslen( m_strLocalPlayerName ) == 0 )
  371.     {
  372.         MessageBox( hDlg, TEXT("You must enter a valid player name."),
  373.                     TEXT("DirectPlay Sample"), MB_OK );
  374.         return S_OK;
  375.     }
  376.  
  377.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  378.  
  379.     iIndex = SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  380.     SendMessage( hWndListBox, LB_GETTEXT, iIndex, (LPARAM)m_strPreferredProvider );
  381.  
  382.     GUID* pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA, iIndex, 0 );
  383.     if( NULL == pGuid )
  384.     {
  385.         // 'Wait for lobby launch' SP has been selected, so wait for a connection
  386.         if( FAILED( hr = m_pLobbiedApp->SetAppAvailable( TRUE, 0 ) ) )
  387.             return DXTRACE_ERR( TEXT("SetAppAvailable"), hr );
  388.  
  389.         // Display the multiplayer connect dialog box.
  390.         DialogBox( m_hInst, MAKEINTRESOURCE(IDD_LOBBY_WAIT_STATUS),
  391.                    hDlg, (DLGPROC) StaticLobbyWaitDlgProc );
  392.  
  393.         if( m_bHaveConnectionSettingsFromLobby )
  394.         {
  395.             if( FAILED( hr = ConnectUsingLobbySettings() ) )
  396.                 return DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  397.  
  398.             return NCW_S_LOBBYCONNECT;
  399.         }
  400.  
  401.         // 'Wait for lobby launch' was canceled, so don't wait for a connection anymore
  402.         if( FAILED( hr = m_pLobbiedApp->SetAppAvailable( FALSE, 0 ) ) )
  403.             return DXTRACE_ERR( TEXT("SetAppAvailable"), hr );
  404.  
  405.         return S_OK;
  406.     }
  407.  
  408.     // Query for the enum host timeout for this SP
  409.     DPN_SP_CAPS dpspCaps;
  410.     ZeroMemory( &dpspCaps, sizeof(DPN_SP_CAPS) );
  411.     dpspCaps.dwSize = sizeof(DPN_SP_CAPS);
  412.     if( FAILED( hr = m_pDP->GetSPCaps( pGuid, &dpspCaps, 0 ) ) )
  413.         return DXTRACE_ERR( TEXT("GetSPCaps"), hr );
  414.  
  415.     // Set the host expire time to around 3 times
  416.     // length of the dwDefaultEnumRetryInterval
  417.     m_dwEnumHostExpireInterval = dpspCaps.dwDefaultEnumRetryInterval * 3;
  418.  
  419.     // Create a device address
  420.     SAFE_RELEASE( m_pDeviceAddress );
  421.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER,
  422.                            IID_IDirectPlay8Address, (LPVOID*) &m_pDeviceAddress );
  423.     if( FAILED(hr) )
  424.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  425.  
  426.     if( FAILED( hr = m_pDeviceAddress->SetSP( pGuid ) ) )
  427.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  428.  
  429.     // Create a host address
  430.     SAFE_RELEASE( m_pHostAddress );
  431.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER,
  432.                            IID_IDirectPlay8Address, (LPVOID*) &m_pHostAddress );
  433.     if( FAILED(hr) )
  434.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  435.  
  436.     if( FAILED( hr = m_pHostAddress->SetSP( pGuid ) ) )
  437.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  438.  
  439.     // The SP has been chosen, so move forward in the wizard
  440.     m_hrDialog = NCW_S_FORWARD;
  441.     EndDialog( hDlg, 0 );
  442.  
  443.     return S_OK;
  444. }
  445.  
  446.  
  447.  
  448.  
  449. //-----------------------------------------------------------------------------
  450. // Name: ConnectionsDlgCleanup()
  451. // Desc: Deletes the connection buffers from the listbox
  452. //-----------------------------------------------------------------------------
  453. VOID CNetConnectWizard::ConnectionsDlgCleanup( HWND hDlg )
  454. {
  455.     GUID*   pGuid = NULL;
  456.     DWORD   iIndex;
  457.     DWORD   dwCount;
  458.  
  459.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  460.  
  461.     dwCount = (DWORD)SendMessage( hWndListBox, LB_GETCOUNT, 0, 0 );
  462.     for( iIndex = 0; iIndex < dwCount; iIndex++ )
  463.     {
  464.         pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA,
  465.                                      iIndex, 0 );
  466.         SAFE_DELETE( pGuid );
  467.     }
  468. }
  469.  
  470.  
  471.  
  472.  
  473. //-----------------------------------------------------------------------------
  474. // Name: StaticSessionsDlgProc()
  475. // Desc: Static msg handler which passes messages
  476. //-----------------------------------------------------------------------------
  477. INT_PTR CALLBACK CNetConnectWizard::StaticSessionsDlgProc( HWND hDlg, UINT uMsg,
  478.                                                            WPARAM wParam, LPARAM lParam )
  479. {
  480.     if( g_pNCW )
  481.         return g_pNCW->SessionsDlgProc( hDlg, uMsg, wParam, lParam );
  482.  
  483.     return FALSE; // Message not handled
  484. }
  485.  
  486.  
  487.  
  488.  
  489. //-----------------------------------------------------------------------------
  490. // Name: SessionsDlgProc()
  491. // Desc: Handles messages fro the multiplayer games dialog
  492. //-----------------------------------------------------------------------------
  493. INT_PTR CALLBACK CNetConnectWizard::SessionsDlgProc( HWND hDlg, UINT msg,
  494.                                                      WPARAM wParam, LPARAM lParam )
  495. {
  496.     HRESULT hr;
  497.  
  498.     switch( msg )
  499.     {
  500.         case WM_INITDIALOG:
  501.             {
  502.                 m_hDlg = hDlg;
  503.  
  504.                 // Load and set the icon
  505.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  506.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  507.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  508.  
  509.                 // Set the window title
  510.                 TCHAR strWindowTitle[256];
  511.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Games"), m_strAppName );
  512.                 SetWindowText( hDlg, strWindowTitle );
  513.  
  514.                 // Init the search portion of the dialog
  515.                 m_bSearchingForSessions = FALSE;
  516.                 SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
  517.                 SessionsDlgInitListbox( hDlg );
  518.             }
  519.             break;
  520.  
  521.         case WM_TIMER:
  522.             // Upon this timer message, then refresh the list of hosts
  523.             // by expiring old hosts, and displaying the list in the
  524.             // dialog box
  525.             if( wParam == TIMERID_DISPLAY_HOSTS )
  526.             {
  527.                 // Don't refresh if we are not enumerating hosts
  528.                 if( !m_bSearchingForSessions )
  529.                     break;
  530.  
  531.                 // Expire all of the hosts that haven't
  532.                 // refreshed in a certain period of time
  533.                 SessionsDlgExpireOldHostEnums();
  534.  
  535.                 // Display the list of hosts in the dialog
  536.                 if( FAILED( hr = SessionsDlgDisplayEnumList( hDlg ) ) )
  537.                 {
  538.                     DXTRACE_ERR( TEXT("SessionsDlgDisplayEnumList"), hr );
  539.                     KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  540.                     MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  541.                                 TEXT("DirectPlay Sample"),
  542.                                 MB_OK | MB_ICONERROR );
  543.                 }
  544.             }
  545.             else if( wParam == TIMERID_CONNECT_COMPLETE )
  546.             {
  547.                 // Check to see if the MessageHandler has set an event to tell us the
  548.                 // DPN_MSGID_CONNECT_COMPLETE has been processed.  Now m_hrConnectComplete
  549.                 // is valid.
  550.                 if( WAIT_OBJECT_0 == WaitForSingleObject( m_hConnectCompleteEvent, 0 ) )
  551.                 {
  552.                     m_bConnecting = FALSE;
  553.  
  554.                     // Re-enable create button
  555.                     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), TRUE );
  556.  
  557.                     if( FAILED( m_hrConnectComplete ) )
  558.                     {
  559.                         DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  560.                         MessageBox( m_hDlg, TEXT("Unable to join game."),
  561.                                     TEXT("DirectPlay Sample"),
  562.                                     MB_OK | MB_ICONERROR );
  563.                     }
  564.                     else
  565.                     {
  566.                         // DirectPlay connect successful, so end dialog
  567.                         m_hrDialog = NCW_S_FORWARD;
  568.                         EndDialog( m_hDlg, 0 );
  569.                     }
  570.  
  571.                     KillTimer( hDlg, TIMERID_CONNECT_COMPLETE );
  572.                 }
  573.             }
  574.  
  575.             break;
  576.  
  577.         case WM_COMMAND:
  578.             switch( LOWORD(wParam) )
  579.             {
  580.                 case IDC_SEARCH_CHECK:
  581.                     m_bSearchingForSessions = !m_bSearchingForSessions;
  582.  
  583.                     if( m_bSearchingForSessions )
  584.                     {
  585.                         SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Searching...") );
  586.  
  587.                         // Start the timer to display the host list every so often
  588.                         SetTimer( hDlg, TIMERID_DISPLAY_HOSTS, DISPLAY_REFRESH_RATE, NULL );
  589.  
  590.                         // Start the async enumeration
  591.                         if( FAILED( hr = SessionsDlgEnumHosts( hDlg ) ) )
  592.                         {
  593.                             DXTRACE_ERR( TEXT("SessionsDlgEnumHosts"), hr );
  594.                             KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  595.                             MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  596.                                         TEXT("DirectPlay Sample"),
  597.                                         MB_OK | MB_ICONERROR );
  598.                         }
  599.                     }
  600.                     else
  601.                     {
  602.                         SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
  603.  
  604.                         // Stop the timer, and stop the async enumeration
  605.                         KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  606.  
  607.                         // Until the CancelAsyncOperation returns, it is possible
  608.                         // to still receive host enumerations
  609.                         if( m_hEnumAsyncOp )
  610.                             m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
  611.  
  612.                         // Reset the search portion of the dialog
  613.                         SessionsDlgInitListbox( hDlg );
  614.                     }
  615.                     break;
  616.  
  617.                 case IDC_GAMES_LIST:
  618.                     if( HIWORD(wParam) != LBN_DBLCLK )
  619.                         break;
  620.                     // Fall through
  621.  
  622.                 case IDC_JOIN:
  623.                     if( FAILED( hr = SessionsDlgJoinGame( hDlg ) ) )
  624.                     {
  625.                         DXTRACE_ERR( TEXT("SessionsDlgJoinGame"), hr );
  626.                         MessageBox( hDlg, TEXT("Unable to join game."),
  627.                                     TEXT("DirectPlay Sample"),
  628.                                     MB_OK | MB_ICONERROR );
  629.                     }
  630.                     break;
  631.  
  632.                 case IDC_CREATE:
  633.                     if( FAILED( hr = SessionsDlgCreateGame( hDlg ) ) )
  634.                     {
  635.                         DXTRACE_ERR( TEXT("SessionsDlgCreateGame"), hr );
  636.                         MessageBox( hDlg, TEXT("Unable to create game."),
  637.                                     TEXT("DirectPlay Sample"),
  638.                                     MB_OK | MB_ICONERROR );
  639.                     }
  640.                     break;
  641.  
  642.                 case IDCANCEL: // The close button was press
  643.                     m_hrDialog = NCW_S_QUIT;
  644.                     EndDialog( hDlg, 0 );
  645.                     break;
  646.  
  647.                 case IDC_BACK: // Cancel button was pressed
  648.                     m_hrDialog = NCW_S_BACKUP;
  649.                     EndDialog( hDlg, 0 );
  650.                     break;
  651.  
  652.                 default:
  653.                     return FALSE; // Message not handled
  654.             }
  655.             break;
  656.  
  657.         case WM_DESTROY:
  658.         {
  659.             KillTimer( hDlg, 1 );
  660.  
  661.             // Cancel the enum hosts search
  662.             // if the enumeration is going on
  663.             if( m_bSearchingForSessions && m_hEnumAsyncOp )
  664.             {
  665.                 m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
  666.                 m_bSearchingForSessions = FALSE;
  667.             }
  668.             break;
  669.         }
  670.  
  671.         default:
  672.             return FALSE; // Message not handled
  673.     }
  674.  
  675.     // Message was handled
  676.     return TRUE;
  677. }
  678.  
  679.  
  680.  
  681.  
  682. //-----------------------------------------------------------------------------
  683. // Name: SessionsDlgInitListbox()
  684. // Desc: Initializes the listbox
  685. //-----------------------------------------------------------------------------
  686. VOID CNetConnectWizard::SessionsDlgInitListbox( HWND hDlg )
  687. {
  688.     HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  689.  
  690.     // Clear the contents from the list box, and
  691.     // display "Looking for games" text in listbox
  692.     SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  693.     if( m_bSearchingForSessions )
  694.     {
  695.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  696.                      (LPARAM) TEXT("Looking for games...") );
  697.     }
  698.     else
  699.     {
  700.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  701.                      (LPARAM) TEXT("Click Start Search to see a list of games.  ")
  702.                               TEXT("Click Create to start a new game.") );
  703.     }
  704.  
  705.     SendMessage( hWndListBox, LB_SETITEMDATA,  0, NULL );
  706.     SendMessage( hWndListBox, LB_SETCURSEL,    0, 0 );
  707.  
  708.     // Disable the join button until sessions are found
  709.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  710. }
  711.  
  712.  
  713.  
  714.  
  715. //-----------------------------------------------------------------------------
  716. // Name: SessionsDlgEnumHosts()
  717. // Desc: Enumerates the DirectPlay sessions, and displays them in the listbox
  718. //-----------------------------------------------------------------------------
  719. HRESULT CNetConnectWizard::SessionsDlgEnumHosts( HWND hDlg )
  720. {
  721.     HRESULT hr;
  722.  
  723.     m_bEnumListChanged = TRUE;
  724.  
  725.     // Enumerate hosts
  726.     DPN_APPLICATION_DESC    dnAppDesc;
  727.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  728.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  729.     dnAppDesc.guidApplication = m_guidApp;
  730.  
  731.     // Enumerate all the active DirectPlay games on the selected connection
  732.     hr = m_pDP->EnumHosts( &dnAppDesc,                            // application description
  733.                            m_pHostAddress,                        // host address
  734.                            m_pDeviceAddress,                      // device address
  735.                            NULL,                                  // pointer to user data
  736.                            0,                                     // user data size
  737.                            INFINITE,                              // retry count (forever)
  738.                            0,                                     // retry interval (0=default)
  739.                            INFINITE,                              // time out (forever)
  740.                            NULL,                                  // user context
  741.                            &m_hEnumAsyncOp,                       // async handle
  742.                            DPNENUMHOSTS_OKTOQUERYFORADDRESSING    // flags
  743.                            );
  744.     if( FAILED(hr) )
  745.         return DXTRACE_ERR( TEXT("EnumHosts"), hr );
  746.  
  747.     return S_OK;
  748. }
  749.  
  750.  
  751.  
  752.  
  753. //-----------------------------------------------------------------------------
  754. // Name: SessionsDlgNoteEnumResponse()
  755. // Desc: Stores them in the linked list, m_DPHostEnumHead.  This is
  756. //       called from the DirectPlay message handler so it could be
  757. //       called simultaneously from multiple threads.
  758. //-----------------------------------------------------------------------------
  759. HRESULT CNetConnectWizard::SessionsDlgNoteEnumResponse( PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg )
  760. {
  761.     HRESULT hr = S_OK;
  762.     BOOL    bFound;
  763.  
  764.     // This function is called from the DirectPlay message handler so it could be
  765.     // called simultaneously from multiple threads, so enter a critical section
  766.     // to assure that it we don't get race conditions.  Locking the entire
  767.     // function is crude, and could be more optimal but is effective for this
  768.     // simple sample
  769.     EnterCriticalSection( &m_csHostEnum );
  770.  
  771.     DPHostEnumInfo* pDPHostEnum          = m_DPHostEnumHead.pNext;
  772.     DPHostEnumInfo* pDPHostEnumNext      = NULL;
  773.     const DPN_APPLICATION_DESC* pResponseMsgAppDesc =
  774.                             pEnumHostsResponseMsg->pApplicationDescription;
  775.  
  776.     // Look for a matching session instance GUID.
  777.     bFound = FALSE;
  778.     while ( pDPHostEnum != &m_DPHostEnumHead )
  779.     {
  780.         if( pResponseMsgAppDesc->guidInstance == pDPHostEnum->pAppDesc->guidInstance )
  781.         {
  782.             bFound = TRUE;
  783.             break;
  784.         }
  785.  
  786.         pDPHostEnumNext = pDPHostEnum;
  787.         pDPHostEnum = pDPHostEnum->pNext;
  788.     }
  789.  
  790.     if( !bFound )
  791.     {
  792.         m_bEnumListChanged = TRUE;
  793.  
  794.         // If there's no match, then look for invalid session and use it
  795.         pDPHostEnum = m_DPHostEnumHead.pNext;
  796.         while ( pDPHostEnum != &m_DPHostEnumHead )
  797.         {
  798.             if( !pDPHostEnum->bValid )
  799.                 break;
  800.  
  801.             pDPHostEnum = pDPHostEnum->pNext;
  802.         }
  803.  
  804.         // If no invalid sessions are found then make a new one
  805.         if( pDPHostEnum == &m_DPHostEnumHead )
  806.         {
  807.             // Found a new session, so create a new node
  808.             pDPHostEnum = new DPHostEnumInfo;
  809.             if( NULL == pDPHostEnum )
  810.             {
  811.                 hr = E_OUTOFMEMORY;
  812.                 goto LCleanup;
  813.             }
  814.  
  815.             ZeroMemory( pDPHostEnum, sizeof(DPHostEnumInfo) );
  816.  
  817.             // Add pDPHostEnum to the circular linked list, m_DPHostEnumHead
  818.             pDPHostEnum->pNext = m_DPHostEnumHead.pNext;
  819.             m_DPHostEnumHead.pNext = pDPHostEnum;
  820.         }
  821.     }
  822.  
  823.     // Update the pDPHostEnum with new information
  824.     TCHAR strName[MAX_PATH];
  825.     if( pResponseMsgAppDesc->pwszSessionName )
  826.     {
  827.         DXUtil_ConvertWideStringToGeneric( strName, pResponseMsgAppDesc->pwszSessionName );
  828.     }
  829.  
  830.     // Cleanup any old enum
  831.     if( pDPHostEnum->pAppDesc )
  832.     {
  833.         SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc->pwszSessionName );
  834.         SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc );
  835.     }
  836.     SAFE_RELEASE( pDPHostEnum->pHostAddr );
  837.     SAFE_RELEASE( pDPHostEnum->pDeviceAddr );
  838.  
  839.     //
  840.     // Duplicate pEnumHostsResponseMsg->pAddressSender in pDPHostEnum->pHostAddr.
  841.     // Duplicate pEnumHostsResponseMsg->pAddressDevice in pDPHostEnum->pDeviceAddr.
  842.     //
  843.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressSender->Duplicate( &pDPHostEnum->pHostAddr ) ) )
  844.     {
  845.         DXTRACE_ERR( TEXT("Duplicate"), hr );
  846.         goto LCleanup;
  847.     }
  848.  
  849.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressDevice->Duplicate( &pDPHostEnum->pDeviceAddr ) ) )
  850.     {
  851.         DXTRACE_ERR( TEXT("Duplicate"), hr );
  852.         goto LCleanup;
  853.     }
  854.  
  855.     // Deep copy the DPN_APPLICATION_DESC from
  856.     pDPHostEnum->pAppDesc = new DPN_APPLICATION_DESC;
  857.     ZeroMemory( pDPHostEnum->pAppDesc, sizeof(DPN_APPLICATION_DESC) );
  858.     memcpy( pDPHostEnum->pAppDesc, pResponseMsgAppDesc, sizeof(DPN_APPLICATION_DESC) );
  859.     if( pResponseMsgAppDesc->pwszSessionName )
  860.     {
  861.         pDPHostEnum->pAppDesc->pwszSessionName = new WCHAR[ wcslen(pResponseMsgAppDesc->pwszSessionName)+1 ];
  862.         wcscpy( pDPHostEnum->pAppDesc->pwszSessionName,
  863.                 pResponseMsgAppDesc->pwszSessionName );
  864.     }
  865.  
  866.     // Update the time this was done, so that we can expire this host
  867.     // if it doesn't refresh w/in a certain amount of time
  868.     pDPHostEnum->dwLastPollTime = timeGetTime();
  869.  
  870.     // Check to see if the current number of players changed
  871.     TCHAR szSessionTemp[MAX_PATH];
  872.     if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
  873.     {
  874.         wsprintf( szSessionTemp, TEXT("%s (%d/%d) (%dms)"), strName,
  875.                   pResponseMsgAppDesc->dwCurrentPlayers,
  876.                   pResponseMsgAppDesc->dwMaxPlayers,
  877.                   pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  878.     }
  879.     else
  880.     {
  881.         wsprintf( szSessionTemp, TEXT("%s (%d) (%dms)"), strName,
  882.                   pResponseMsgAppDesc->dwCurrentPlayers,
  883.                   pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  884.     }
  885.  
  886.     // if this node was previously invalidated, or the session name is now
  887.     // different the session list in the dialog needs to be updated
  888.     if( ( pDPHostEnum->bValid == FALSE ) ||
  889.         ( _tcscmp( pDPHostEnum->szSession, szSessionTemp ) != 0 ) )
  890.     {
  891.         m_bEnumListChanged = TRUE;
  892.     }
  893.     _tcscpy( pDPHostEnum->szSession, szSessionTemp );
  894.  
  895.     // This host is now valid
  896.     pDPHostEnum->bValid = TRUE;
  897.  
  898. LCleanup:
  899.     LeaveCriticalSection( &m_csHostEnum );
  900.  
  901.     return hr;
  902. }
  903.  
  904.  
  905.  
  906.  
  907. //-----------------------------------------------------------------------------
  908. // Name: SessionsDlgExpireOldHostEnums
  909. // Desc: Check all nodes to see if any have expired yet.
  910. //-----------------------------------------------------------------------------
  911. VOID CNetConnectWizard::SessionsDlgExpireOldHostEnums()
  912. {
  913.     DWORD dwCurrentTime = timeGetTime();
  914.  
  915.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  916.     // is called from the DirectPlay message handler threads so
  917.     // they may also be inside it at this time, so we need to go into the
  918.     // critical section first
  919.     EnterCriticalSection( &m_csHostEnum );
  920.  
  921.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  922.     while ( pDPHostEnum != &m_DPHostEnumHead )
  923.     {
  924.         // Check the poll time to expire stale entries.  Also check to see if
  925.         // the entry is already invalid.  If so, don't note that the enum list
  926.         // changed because that causes the list in the dialog to constantly redraw.
  927.         if( ( pDPHostEnum->bValid != FALSE ) &&
  928.             ( pDPHostEnum->dwLastPollTime < dwCurrentTime - m_dwEnumHostExpireInterval ) )
  929.         {
  930.             // This node has expired, so invalidate it.
  931.             pDPHostEnum->bValid = FALSE;
  932.             m_bEnumListChanged  = TRUE;
  933.         }
  934.  
  935.         pDPHostEnum = pDPHostEnum->pNext;
  936.     }
  937.  
  938.     LeaveCriticalSection( &m_csHostEnum );
  939. }
  940.  
  941.  
  942.  
  943.  
  944. //-----------------------------------------------------------------------------
  945. // Name: SessionsDlgDisplayEnumList
  946. // Desc: Display the list of hosts in the dialog box
  947. //-----------------------------------------------------------------------------
  948. HRESULT CNetConnectWizard::SessionsDlgDisplayEnumList( HWND hDlg )
  949. {
  950.     HWND           hWndListBox   = GetDlgItem( hDlg, IDC_GAMES_LIST );
  951.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  952.     GUID           guidSelectedInstance;
  953.     BOOL           bFindSelectedGUID;
  954.     BOOL           bFoundSelectedGUID;
  955.     int            nItemSelected;
  956.  
  957.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  958.     // is called from the DirectPlay message handler threads so
  959.     // they may also be inside it at this time, so we need to go into the
  960.     // critical section first
  961.     EnterCriticalSection( &m_csHostEnum );
  962.  
  963.     // Only update the display list if it has changed since last time
  964.     if( !m_bEnumListChanged )
  965.     {
  966.         LeaveCriticalSection( &m_csHostEnum );
  967.         return S_OK;
  968.     }
  969.  
  970.     m_bEnumListChanged = FALSE;
  971.  
  972.     bFindSelectedGUID  = FALSE;
  973.     bFoundSelectedGUID = FALSE;
  974.  
  975.     // Try to keep the same session selected unless it goes away or
  976.     // there is no real session currently selected
  977.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  978.     if( nItemSelected != LB_ERR )
  979.     {
  980.         pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  981.                                                              nItemSelected, 0 );
  982.         if( pDPHostEnumSelected != NULL && pDPHostEnumSelected->bValid )
  983.         {
  984.             guidSelectedInstance = pDPHostEnumSelected->pAppDesc->guidInstance;
  985.             bFindSelectedGUID = TRUE;
  986.         }
  987.     }
  988.  
  989.     // Tell listbox not to redraw itself since the contents are going to change
  990.     SendMessage( hWndListBox, WM_SETREDRAW, FALSE, 0 );
  991.  
  992.     // Test to see if any sessions exist in the linked list
  993.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  994.     while ( pDPHostEnum != &m_DPHostEnumHead )
  995.     {
  996.         if( pDPHostEnum->bValid )
  997.             break;
  998.         pDPHostEnum = pDPHostEnum->pNext;
  999.     }
  1000.  
  1001.     // If there are any sessions in list,
  1002.     // then add them to the listbox
  1003.     if( pDPHostEnum != &m_DPHostEnumHead )
  1004.     {
  1005.         // Clear the contents from the list box and enable the join button
  1006.         SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  1007.  
  1008.         // Enable the join button only if not already connecting to a game
  1009.         if( !m_bConnecting )
  1010.             EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), TRUE );
  1011.  
  1012.         pDPHostEnum = m_DPHostEnumHead.pNext;
  1013.         while ( pDPHostEnum != &m_DPHostEnumHead )
  1014.         {
  1015.             // Add host to list box if it is valid
  1016.             if( pDPHostEnum->bValid )
  1017.             {
  1018.                 int nIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  1019.                                                (LPARAM)pDPHostEnum->szSession );
  1020.                 SendMessage( hWndListBox, LB_SETITEMDATA, nIndex, (LPARAM)pDPHostEnum );
  1021.  
  1022.                 if( bFindSelectedGUID )
  1023.                 {
  1024.                     // Look for the session the was selected before
  1025.                     if( pDPHostEnum->pAppDesc->guidInstance == guidSelectedInstance )
  1026.                     {
  1027.                         SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
  1028.                         bFoundSelectedGUID = TRUE;
  1029.                     }
  1030.                 }
  1031.             }
  1032.  
  1033.             pDPHostEnum = pDPHostEnum->pNext;
  1034.         }
  1035.  
  1036.         if( !bFindSelectedGUID || !bFoundSelectedGUID )
  1037.             SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  1038.     }
  1039.     else
  1040.     {
  1041.         // There are no active session, so just reset the listbox
  1042.         SessionsDlgInitListbox( hDlg );
  1043.     }
  1044.  
  1045.     // Tell listbox to redraw itself now since the contents have changed
  1046.     SendMessage( hWndListBox, WM_SETREDRAW, TRUE, 0 );
  1047.     InvalidateRect( hWndListBox, NULL, FALSE );
  1048.  
  1049.     LeaveCriticalSection( &m_csHostEnum );
  1050.  
  1051.     return S_OK;
  1052. }
  1053.  
  1054.  
  1055.  
  1056.  
  1057. //-----------------------------------------------------------------------------
  1058. // Name: SessionsDlgJoinGame()
  1059. // Desc: Joins the selected DirectPlay session
  1060. //-----------------------------------------------------------------------------
  1061. HRESULT CNetConnectWizard::SessionsDlgJoinGame( HWND hDlg )
  1062. {
  1063.     HRESULT         hr;
  1064.     HWND            hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  1065.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  1066.     int             nItemSelected;
  1067.     DWORD           dwPort = 0;
  1068.  
  1069.     m_bHostPlayer = FALSE;
  1070.  
  1071.     // Add status text in list box
  1072.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  1073.  
  1074.     EnterCriticalSection( &m_csHostEnum );
  1075.  
  1076.     pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  1077.                                                          nItemSelected, 0 );
  1078.  
  1079.     if( NULL == pDPHostEnumSelected )
  1080.     {
  1081.         LeaveCriticalSection( &m_csHostEnum );
  1082.         MessageBox( hDlg, TEXT("There are no games to join."),
  1083.                     TEXT("DirectPlay Sample"), MB_OK );
  1084.         return S_OK;
  1085.     }
  1086.  
  1087.     m_bConnecting = TRUE;
  1088.  
  1089.     // Set the peer info
  1090.     WCHAR wszPeerName[MAX_PATH];
  1091.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1092.  
  1093.     DPN_PLAYER_INFO dpPlayerInfo;
  1094.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1095.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1096.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1097.     dpPlayerInfo.pwszName = wszPeerName;
  1098.  
  1099.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1100.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1101.     // be set by the time we call Connect() below.
  1102.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1103.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1104.  
  1105.     ResetEvent( m_hConnectCompleteEvent );
  1106.  
  1107.     // Connect to an existing session. DPNCONNECT_OKTOQUERYFORADDRESSING allows
  1108.     // DirectPlay to prompt the user using a dialog box for any device address
  1109.     // or host address information that is missing
  1110.     // We also pass in copies of the app desc and host addr, since pDPHostEnumSelected
  1111.     // might be deleted from another thread that calls SessionsDlgExpireOldHostEnums().
  1112.     // This process could also be done using reference counting instead.
  1113.     hr = m_pDP->Connect( pDPHostEnumSelected->pAppDesc,       // the application desc
  1114.                          pDPHostEnumSelected->pHostAddr,      // address of the host of the session
  1115.                          pDPHostEnumSelected->pDeviceAddr,    // address of the local device the enum responses were received on
  1116.                          NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1117.                          NULL, 0,                             // user data, user data size
  1118.                          NULL,                                // player context,
  1119.                          NULL, &m_hConnectAsyncOp,            // async context, async handle,
  1120.                          DPNCONNECT_OKTOQUERYFORADDRESSING ); // flags
  1121.     if( hr != E_PENDING && FAILED(hr) )
  1122.         return DXTRACE_ERR( TEXT("Connect"), hr );
  1123.  
  1124.     LeaveCriticalSection( &m_csHostEnum );
  1125.  
  1126.     // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  1127.     // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  1128.     // which lets us know if the connect was successful or not.
  1129.     SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  1130.  
  1131.     // Disable the create/join buttons until connect succeeds or fails
  1132.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  1133.     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), FALSE );
  1134.  
  1135.     return S_OK;
  1136. }
  1137.  
  1138.  
  1139.  
  1140.  
  1141. //-----------------------------------------------------------------------------
  1142. // Name: SessionsDlgCreateGame()
  1143. // Desc: Asks the user the session name, and creates a new DirectPlay session
  1144. //-----------------------------------------------------------------------------
  1145. HRESULT CNetConnectWizard::SessionsDlgCreateGame( HWND hDlg )
  1146. {
  1147.     HRESULT hr;
  1148.     int     nResult;
  1149.  
  1150.     // Display a modal multiplayer connect dialog box.
  1151.     EnableWindow( hDlg, FALSE );
  1152.     nResult = (int)DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CREATE),
  1153.                               hDlg, (DLGPROC) StaticCreateSessionDlgProc );
  1154.     EnableWindow( hDlg, TRUE );
  1155.  
  1156.     if( nResult == IDCANCEL )
  1157.         return S_OK;
  1158.  
  1159.     // Stop the search if we are about to connect
  1160.     if( m_bSearchingForSessions )
  1161.     {
  1162.         CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  1163.         SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
  1164.     }
  1165.  
  1166.     m_bHostPlayer = TRUE;
  1167.  
  1168.     // Set peer info name
  1169.     WCHAR wszPeerName[MAX_PATH];
  1170.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1171.  
  1172.     DPN_PLAYER_INFO dpPlayerInfo;
  1173.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1174.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1175.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1176.     dpPlayerInfo.pwszName = wszPeerName;
  1177.  
  1178.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1179.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1180.     // be set by the time we call Host() below.
  1181.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1182.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1183.  
  1184.     WCHAR wszSessionName[MAX_PATH];
  1185.     DXUtil_ConvertGenericStringToWide( wszSessionName, m_strSessionName );
  1186.  
  1187.     // Setup the application desc
  1188.     DPN_APPLICATION_DESC dnAppDesc;
  1189.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1190.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  1191.     dnAppDesc.guidApplication = m_guidApp;
  1192.     dnAppDesc.pwszSessionName = wszSessionName;
  1193.     dnAppDesc.dwMaxPlayers    = m_dwMaxPlayers;
  1194.     dnAppDesc.dwFlags         = 0;
  1195.     if( m_bMigrateHost )
  1196.         dnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1197.  
  1198.     // Host a game on m_pDeviceAddress as described by dnAppDesc
  1199.     // DPNHOST_OKTOQUERYFORADDRESSING allows DirectPlay to prompt the user
  1200.     // using a dialog box for any device address information that is missing
  1201.     if( FAILED( hr = m_pDP->Host( &dnAppDesc,               // the application desc
  1202.                                   &m_pDeviceAddress,        // array of addresses of the local devices used to connect to the host
  1203.                                   1,                        // number in array
  1204.                                   NULL, NULL,               // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1205.                                   NULL,                     // player context
  1206.                                   DPNHOST_OKTOQUERYFORADDRESSING ) ) ) // flags
  1207.         return DXTRACE_ERR( TEXT("Host"), hr );
  1208.  
  1209.     // DirectPlay connect successful, so end dialog
  1210.     m_hrDialog = NCW_S_FORWARD;
  1211.     EndDialog( hDlg, 0 );
  1212.  
  1213.     return S_OK;
  1214. }
  1215.  
  1216.  
  1217.  
  1218.  
  1219. //-----------------------------------------------------------------------------
  1220. // Name: StaticConnectionsDlgProc()
  1221. // Desc: Static msg handler which passes messages
  1222. //-----------------------------------------------------------------------------
  1223. INT_PTR CALLBACK CNetConnectWizard::StaticCreateSessionDlgProc( HWND hDlg, UINT uMsg,
  1224.                                                                 WPARAM wParam, LPARAM lParam )
  1225. {
  1226.     if( g_pNCW )
  1227.         return g_pNCW->CreateSessionDlgProc( hDlg, uMsg, wParam, lParam );
  1228.  
  1229.     return FALSE; // Message not handled
  1230. }
  1231.  
  1232.  
  1233.  
  1234.  
  1235. //-----------------------------------------------------------------------------
  1236. // Name: CreateSessionDlgProc()
  1237. // Desc: Handles messages fro the multiplayer create game dialog
  1238. //-----------------------------------------------------------------------------
  1239. INT_PTR CALLBACK CNetConnectWizard::CreateSessionDlgProc( HWND hDlg, UINT msg,
  1240.                                                           WPARAM wParam, LPARAM lParam )
  1241. {
  1242.     DWORD dwNameLength;
  1243.  
  1244.     switch( msg )
  1245.     {
  1246.         case WM_INITDIALOG:
  1247.             SetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME, m_strSessionName );
  1248.             CheckDlgButton( hDlg, IDC_MIGRATE_HOST, BST_CHECKED );
  1249.             return TRUE;
  1250.  
  1251.         case WM_COMMAND:
  1252.             switch( LOWORD(wParam) )
  1253.             {
  1254.                 case IDOK:
  1255.                     dwNameLength = GetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME,
  1256.                                                    m_strSessionName,
  1257.                                                    MAX_PATH );
  1258.                     if( dwNameLength == 0 )
  1259.                         return TRUE; // Don't accept blank session names
  1260.  
  1261.                     m_bMigrateHost = ( IsDlgButtonChecked( hDlg,
  1262.                                        IDC_MIGRATE_HOST ) == BST_CHECKED );
  1263.  
  1264.                     EndDialog( hDlg, IDOK );
  1265.                     return TRUE;
  1266.  
  1267.                 case IDCANCEL:
  1268.                     EndDialog( hDlg, IDCANCEL );
  1269.                     return TRUE;
  1270.             }
  1271.             break;
  1272.     }
  1273.  
  1274.     return FALSE; // Didn't handle message
  1275. }
  1276.  
  1277.  
  1278.  
  1279.  
  1280. //-----------------------------------------------------------------------------
  1281. // Name: SessionsDlgEnumListCleanup()
  1282. // Desc: Deletes the linked list, g_DPHostEnumInfoHead
  1283. //-----------------------------------------------------------------------------
  1284. VOID CNetConnectWizard::SessionsDlgEnumListCleanup()
  1285. {
  1286.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  1287.     DPHostEnumInfo* pDPHostEnumDelete;
  1288.  
  1289.     while ( pDPHostEnum != &m_DPHostEnumHead )
  1290.     {
  1291.         pDPHostEnumDelete = pDPHostEnum;
  1292.         pDPHostEnum = pDPHostEnum->pNext;
  1293.  
  1294.         if( pDPHostEnumDelete->pAppDesc )
  1295.         {
  1296.             SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc->pwszSessionName );
  1297.             SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc );
  1298.         }
  1299.  
  1300.         // Changed from array delete to Release
  1301.         SAFE_RELEASE( pDPHostEnumDelete->pHostAddr );
  1302.         SAFE_RELEASE( pDPHostEnumDelete->pDeviceAddr );
  1303.         SAFE_DELETE( pDPHostEnumDelete );
  1304.     }
  1305.  
  1306.     // Re-link the g_DPHostEnumInfoHead circular linked list
  1307.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  1308. }
  1309.  
  1310.  
  1311.  
  1312.  
  1313. //-----------------------------------------------------------------------------
  1314. // Name: MessageHandler
  1315. // Desc: Handler for DirectPlay messages.  This function is called by
  1316. //       the DirectPlay message handler pool of threads, so be careful of thread
  1317. //       synchronization problems with shared memory
  1318. //-----------------------------------------------------------------------------
  1319. HRESULT WINAPI CNetConnectWizard::MessageHandler( PVOID pvUserContext,
  1320.                                                   DWORD dwMessageId,
  1321.                                                   PVOID pMsgBuffer )
  1322. {
  1323.     // Try not to stay in this message handler for too long, otherwise
  1324.     // there will be a backlog of data.  The best solution is to
  1325.     // queue data as it comes in, and then handle it on other threads.
  1326.  
  1327.     // This function is called by the DirectPlay message handler pool of
  1328.     // threads, so be careful of thread synchronization problems with shared memory
  1329.  
  1330.     switch(dwMessageId)
  1331.     {
  1332.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  1333.         {
  1334.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
  1335.             pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
  1336.  
  1337.             // Take note of the host response
  1338.             SessionsDlgNoteEnumResponse( pEnumHostsResponseMsg );
  1339.             break;
  1340.         }
  1341.  
  1342.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  1343.         {
  1344.             PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
  1345.             pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
  1346.  
  1347.             if( pAsyncOpCompleteMsg->hAsyncOp == m_hEnumAsyncOp )
  1348.             {
  1349.                 SessionsDlgEnumListCleanup();
  1350.  
  1351.                 // The user canceled the DirectPlay connection dialog,
  1352.                 // so stop the search
  1353.                 if( m_bSearchingForSessions )
  1354.                 {
  1355.                     CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  1356.                     SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
  1357.                 }
  1358.  
  1359.                 m_hEnumAsyncOp = NULL;
  1360.                 m_bSearchingForSessions = FALSE;
  1361.             }
  1362.             break;
  1363.         }
  1364.  
  1365.         case DPN_MSGID_CONNECT_COMPLETE:
  1366.         {
  1367.             PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
  1368.             pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
  1369.  
  1370.             // Set m_hrConnectComplete, then set an event letting
  1371.             // everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
  1372.             // has been handled
  1373.             m_hrConnectComplete = pConnectCompleteMsg->hResultCode;
  1374.             SetEvent( m_hConnectCompleteEvent );
  1375.             break;
  1376.         }
  1377.     }
  1378.  
  1379.     return S_OK;
  1380. }
  1381.  
  1382.  
  1383.  
  1384.  
  1385. //-----------------------------------------------------------------------------
  1386. // Name: ConnectUsingLobbySettings
  1387. // Desc: Call this after the DPL_MSGID_CONNECT has been processed to carry out
  1388. //       the connection settings received by the lobby client.  DPL_MSGID_CONNECT
  1389. //       will have already been processed if we were lobby launched, or after
  1390. //       WaitForConnection returns without timing out.
  1391. //-----------------------------------------------------------------------------
  1392. HRESULT CNetConnectWizard::ConnectUsingLobbySettings()
  1393. {
  1394.     HRESULT hr;
  1395.     DPNHANDLE hAsync;
  1396.  
  1397.     if( m_hLobbyClient == NULL )
  1398.         return E_INVALIDARG;
  1399.  
  1400.     DPL_CONNECTION_SETTINGS* pSettings = NULL;
  1401.     DWORD dwSettingsSize = 0;
  1402.  
  1403.     // Get the connection settings from the lobby.
  1404.     hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 );
  1405.     if( hr != DPNERR_BUFFERTOOSMALL )
  1406.         return DXTRACE_ERR( TEXT("GetConnectionSettings"), hr );
  1407.     pSettings = (DPL_CONNECTION_SETTINGS*) new BYTE[dwSettingsSize];
  1408.     if( FAILED( hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 ) ) )
  1409.         return DXTRACE_ERR( TEXT("GetConnectionSettings"), hr );
  1410.  
  1411.     // Check if the lobby told us to host the game
  1412.     m_bHostPlayer = (pSettings->dwFlags & DPLCONNECTSETTINGS_HOST);
  1413.  
  1414.     // Set the peer info
  1415.     WCHAR wszPeerName[MAX_PATH];
  1416.     DXUtil_ConvertGenericStringToWide( wszPeerName, m_strLocalPlayerName );
  1417.     DPN_PLAYER_INFO dpPlayerInfo;
  1418.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1419.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1420.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1421.     dpPlayerInfo.pwszName = wszPeerName;
  1422.  
  1423.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1424.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1425.     // be set by the time we call Connect() below.
  1426.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1427.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  1428.  
  1429.     if( m_bHostPlayer )
  1430.     {
  1431.         // Enable host migrate by default.
  1432.         pSettings->dpnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1433.  
  1434.         // Host a game as described by pSettings
  1435.         if( FAILED( hr = m_pDP->Host( &pSettings->dpnAppDesc,               // the application desc
  1436.                                       pSettings->ppdp8DeviceAddresses,      // array of addresses of the local devices used to connect to the host
  1437.                                       pSettings->cNumDeviceAddresses,       // number in array
  1438.                                       NULL, NULL,                           // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1439.                                       NULL,                                 // player context
  1440.                                       0 ) ) )                               // flags
  1441.             return DXTRACE_ERR( TEXT("Host"), hr );
  1442.     }
  1443.     else
  1444.     {
  1445.         // Connect to an existing session. There should only be on device address in
  1446.         // the connection settings structure when connecting to a session, so just
  1447.         // pass in the first one.
  1448.         // The enumeration is automatically cancelled after Connect is called 
  1449.         hr = m_pDP->Connect( &pSettings->dpnAppDesc,              // the application desc
  1450.                              pSettings->pdp8HostAddress,          // address of the host of the session
  1451.                              pSettings->ppdp8DeviceAddresses[0],  // address of the local device used to connect to the host
  1452.                              NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1453.                              NULL, 0,                             // user data, user data size
  1454.                              NULL,                                // player context,
  1455.                              NULL, &hAsync,                       // async context, async handle,
  1456.                              0 );                                 // flags
  1457.         if( hr != E_PENDING && FAILED(hr) )
  1458.             return DXTRACE_ERR( TEXT("Connect"), hr );
  1459.         hr = S_OK; // Accept E_PENDING.
  1460.  
  1461.         // Wait until the MessageHandler sets an event to tell us the
  1462.         // DPN_MSGID_CONNECT_COMPLETE has been processed.  Then m_hrConnectComplete
  1463.         // will be valid.
  1464.         WaitForSingleObject( m_hConnectCompleteEvent, INFINITE );
  1465.  
  1466.         if( FAILED( m_hrConnectComplete ) )
  1467.         {
  1468.             DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  1469.             MessageBox( m_hDlg, TEXT("Unable to join game."),
  1470.                         TEXT("DirectPlay Sample"),
  1471.                         MB_OK | MB_ICONERROR );
  1472.             hr = m_hrConnectComplete;
  1473.         }
  1474.     }
  1475.  
  1476.     // Cleanup the addresses and memory obtained from GetConnectionSettings
  1477.     SAFE_RELEASE( pSettings->pdp8HostAddress );
  1478.     for( DWORD dwIndex=0; dwIndex < pSettings->cNumDeviceAddresses; dwIndex++ )
  1479.     {
  1480.         SAFE_RELEASE( pSettings->ppdp8DeviceAddresses[dwIndex] );
  1481.     }
  1482.  
  1483.     SAFE_DELETE_ARRAY( pSettings );
  1484.  
  1485.     return hr;
  1486. }
  1487.  
  1488.  
  1489.  
  1490.  
  1491. //-----------------------------------------------------------------------------
  1492. // Name: LobbyMessageHandler
  1493. // Desc: Handler for DirectPlay messages.  This function is called by
  1494. //       the DirectPlay lobby message handler pool of threads, so be careful of thread
  1495. //       synchronization problems with shared memory
  1496. //-----------------------------------------------------------------------------
  1497. HRESULT WINAPI CNetConnectWizard::LobbyMessageHandler( PVOID pvUserContext,
  1498.                                                        DWORD dwMessageId,
  1499.                                                        PVOID pMsgBuffer )
  1500. {
  1501.     HRESULT hr = S_OK;
  1502.  
  1503.     switch(dwMessageId)
  1504.     {
  1505.         case DPL_MSGID_CONNECT:
  1506.         {
  1507.             // This message will be processed when a lobby connection has been
  1508.             // established. If you were lobby launched then
  1509.             // IDirectPlay8LobbiedApplication::Initialize()
  1510.             // waits until this message has been processed before returning, so
  1511.             // take care not to deadlock by making calls that need to be handled by
  1512.             // the thread who called Initialize().  The same is true for WaitForConnection()
  1513.  
  1514.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1515.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1516.             PDPL_CONNECTION_SETTINGS pSettings = pConnectMsg->pdplConnectionSettings;
  1517.  
  1518.             m_hLobbyClient = pConnectMsg->hConnectId;
  1519.  
  1520.             if( FAILED( hr = m_pDP->RegisterLobby( m_hLobbyClient, m_pLobbiedApp,
  1521.                                                    DPNLOBBY_REGISTER ) ) )
  1522.                 return DXTRACE_ERR( TEXT("RegisterLobby"), hr );
  1523.  
  1524.             if( pSettings == NULL )
  1525.             {
  1526.                 // There aren't connection settings from the lobby
  1527.                 m_bHaveConnectionSettingsFromLobby = FALSE;
  1528.             }
  1529.             else
  1530.             {
  1531.                 // Record the player name if found
  1532.                 if( pSettings->pwszPlayerName != NULL )
  1533.                 {
  1534.                     TCHAR strPlayerName[MAX_PATH];
  1535.                     DXUtil_ConvertWideStringToGeneric( strPlayerName, pSettings->pwszPlayerName );
  1536.                     _tcscpy( m_strLocalPlayerName, strPlayerName );
  1537.                 }
  1538.                 else
  1539.                 {
  1540.                     _tcscpy( m_strLocalPlayerName, TEXT("Unknown player name") );
  1541.                 }
  1542.  
  1543.                 m_bHaveConnectionSettingsFromLobby = TRUE;
  1544.             }
  1545.  
  1546.             // Tell everyone we have a lobby connection now
  1547.             SetEvent( m_hLobbyConnectionEvent );
  1548.             break;
  1549.         }
  1550.     }
  1551.  
  1552.     return S_OK;
  1553. }
  1554.  
  1555.  
  1556.  
  1557. //-----------------------------------------------------------------------------
  1558. // Name: StaticLobbyWaitDlgProc()
  1559. // Desc: Static msg handler which passes messages
  1560. //-----------------------------------------------------------------------------
  1561. INT_PTR CALLBACK CNetConnectWizard::StaticLobbyWaitDlgProc( HWND hDlg, UINT uMsg,
  1562.                                                                 WPARAM wParam, LPARAM lParam )
  1563. {
  1564.     if( g_pNCW )
  1565.         return g_pNCW->LobbyWaitDlgProc( hDlg, uMsg, wParam, lParam );
  1566.  
  1567.     return FALSE; // Message not handled
  1568. }
  1569.  
  1570.  
  1571.  
  1572.  
  1573. //-----------------------------------------------------------------------------
  1574. // Name: LobbyWaitDlgProc()
  1575. // Desc: Handles messages for the lobby wait status dialog
  1576. //-----------------------------------------------------------------------------
  1577. INT_PTR CALLBACK CNetConnectWizard::LobbyWaitDlgProc( HWND hDlg, UINT msg,
  1578.                                                       WPARAM wParam, LPARAM lParam )
  1579. {
  1580.     switch( msg )
  1581.     {
  1582.         case WM_INITDIALOG:
  1583.             // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  1584.             // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  1585.             // which lets us know if the connect was successful or not.
  1586.             SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  1587.  
  1588.             SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Waiting for lobby connection...") );
  1589.             return TRUE;
  1590.  
  1591.         case WM_COMMAND:
  1592.             switch( LOWORD(wParam) )
  1593.             {
  1594.                 case IDCANCEL:
  1595.                     EndDialog( hDlg, IDCANCEL );
  1596.                     return TRUE;
  1597.             }
  1598.             break;
  1599.  
  1600.         case WM_TIMER:
  1601.         {
  1602.             if( wParam == TIMERID_CONNECT_COMPLETE )
  1603.             {
  1604.                 // Wait for a lobby connection.  If this call
  1605.                 // returns WAIT_OBJECT_0 then the DPL_MSGID_CONNECT will
  1606.                 // have already been processed.
  1607.                 DWORD dwResult = WaitForSingleObject( m_hLobbyConnectionEvent, 100 );
  1608.                 if( dwResult != WAIT_TIMEOUT )
  1609.                     EndDialog( hDlg, IDOK );
  1610.             }
  1611.             break;
  1612.         }
  1613.     }
  1614.  
  1615.     return FALSE; // Didn't handle message
  1616. }
  1617.  
  1618.  
  1619.  
  1620.  
  1621.